﻿using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Collections;
using System.Web;
using MindTouch.Dream;
using System.Threading;
using MindTouch.Tasking;

namespace Morange.Async {
    using Yield = IEnumerator<IYield>;
    /// <summary>
    /// Summary description for AsyncCore
    /// </summary>
    public class AsyncCore
    {
        private static Queue tasks = new Queue();
        private static System.Threading.AutoResetEvent waiting;
        public static bool IsRunning;
        static log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        static AsyncCore()
        {            
            ThreadStart ts = new ThreadStart(run);
            Thread t = new Thread(ts);
            t.Start();
        }

        /// <summary>
        /// Call this to instanise Class contructor and start main loop
        /// </summary>
        public static void init()
        {
            //dummy init
            
        }

        public static void stop()
        {
            IsRunning = false;
            tasks.Clear();
            waiting.Set();
        }

        private AsyncCore()
        {
            // Make Singleton
        }

        public static AsyncCoreResult AddAsyncPage(HttpContext context, AsyncCallback cb, CoroutineHandler<AsyncCoreResult, Result> process, object extraData)
        {
            log.Debug("StartAsyncPage");
            AsyncCoreResult r = new AsyncCoreResult(context, cb, process, extraData);
            tasks.Enqueue(r);            
            
            try
            {
                log.Debug("EndAsyncPage");
                return r;
            }
            finally
            {
                log.Debug("EndAsyncPageFinal");
                waiting.Set();
            }            
        }

        private static void run()
        {
            IsRunning = true;
            waiting = new AutoResetEvent(false);
            while (IsRunning)
            {
                if (tasks.Count > 0)
                {
                    AsyncCoreResult task = (AsyncCoreResult)tasks.Dequeue();
                    Result result = new Result();
                    task.result = result;
                    result.WhenDone(delegate {
                        log.Debug("InvokeDone");
                        if(result.HasException)
                        {
                            log.Error("AsyncError: " + result.Exception.ToString());
                            task.cb(task);
                        }
                        result.Return();
                    });
                    log.Debug("BeforeInvoke");
                    Coroutine.Invoke<AsyncCoreResult, Result>(task.process, task, result);
                    log.Debug("EndInvoke");
                }
                else
                {
                    if (waiting != null)
                    {
                        waiting.WaitOne();
                    }
                }
            }
        }
    }


}

